﻿using System;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Windows.Input;
using Notoric.Gui.Windows;

namespace Notoric.Gui.Commands
{
    /// <summary>
    /// Implements a command that saves the currently open project.
    /// </summary>
    /// <remarks>
    /// <para>
    /// The command can execute if the Projects collection of the Project Explorer window
    /// contains exactly 1 <see cref="Notoric.ViewModel.Elements.Project"/> instance
    /// and the <see cref="Notoric.ViewModel.Elements.Project.IsModified"/> flag of this instance
    /// is <see langword="true"/>.
    /// </para>
    /// <para>
    /// The execution proceeds as follows:
    /// <list type="number">
    /// <item>
    /// If the <see cref="Notoric.ViewModel.Elements.Project.FileName"/> property is not <see langword="null"/>,
    /// the command calls the <see cref="Notoric.ViewModel.Elements.Project.Save"/> method.
    /// Otherwise, it executes the <see cref="SaveAsCommand"/>.
    /// </item>
    /// </list>
    /// </para>
    /// </remarks>
    public class SaveCommand : RibbonCommand
    {
        #region Constructors

        /// <summary>
        /// Creates a new <see cref="SaveCommand"/> instance.
        /// </summary>
        /// <param name="mainWindow">
        /// <para>
        /// Type: <see cref="MainWindow"/>
        /// </para>
        /// <para>
        /// Reference to the application's main window.
        /// </para>
        /// </param>
        /// <exception cref="ArgumentNullException">
        /// The <paramref name="mainWindow"/> is <see langword="null"/>.
        /// </exception>
        public SaveCommand(MainWindow mainWindow)
            : base(mainWindow)
        {
            ApplicationWindow.ProjectExplorer.Projects.CollectionChanged += new NotifyCollectionChangedEventHandler(Projects_CollectionChanged);
            if (ApplicationWindow.ProjectExplorer.Projects.Count > 0)
                ApplicationWindow.ProjectExplorer.Projects[0].PropertyChanged += new PropertyChangedEventHandler(Project_PropertyChanged);
        }

        #endregion

        #region ICommand Members

        /// <inheritdoc/>
        public override bool CanExecute(object parameter)
        {
            return ApplicationWindow.ProjectExplorer.Projects.Count == 1 && ApplicationWindow.ProjectExplorer.Projects[0].IsModified;
        }

        /// <inheritdoc/>
        public override void Execute(object parameter)
        {
            var project = ApplicationWindow.ProjectExplorer.Projects[0];

            if (project.FileName != null)
            {
                Mouse.OverrideCursor = Cursors.Wait;
                project.Save();
                Mouse.OverrideCursor = null;
            }
            else
                ApplicationWindow.SaveAsCmd.Execute(null);
        }

        #endregion

        #region Event Handlers

        /// <summary>
        /// Occurs when the value of a property of an open project has changed.
        /// </summary>
        /// <param name="sender">Object that has sent the event</param>
        /// <param name="e">Event data</param>
        private void Project_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == "IsModified")
                RaiseCanExecuteChanged();
        }

        /// <summary>
        /// Occurs when the collection of open projects has changed.
        /// </summary>
        /// <param name="sender">Object that has sent the event</param>
        /// <param name="e">Event data</param>
        private void Projects_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            if (e.Action == NotifyCollectionChangedAction.Remove || e.Action == NotifyCollectionChangedAction.Replace)
                ((ViewModel.Elements.Project)(e.OldItems[0])).PropertyChanged -= Project_PropertyChanged;
            if (e.Action == NotifyCollectionChangedAction.Add || e.Action == NotifyCollectionChangedAction.Replace)
                ((ViewModel.Elements.Project)(e.NewItems[0])).PropertyChanged += new PropertyChangedEventHandler(Project_PropertyChanged);

            RaiseCanExecuteChanged();
        }

        #endregion
    }
}
